package com.personal.core.queueextend;

import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.io.Serializable;
import java.util.AbstractQueue;
import java.util.Collection;
import java.util.Iterator;
import java.util.NoSuchElementException;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.ReentrantLock;

/**
 * 可以插入的双端队列
 * @author cuibo
 *
 * @param <T>
 */
@SuppressWarnings("unchecked")
public class PluggableLinkedBlockingDueue<T> extends AbstractQueue<T> implements IplugBlockingDueue<T>, Serializable
{
    /**
     * 
     */
    private static final long serialVersionUID = -6616584793874682799L;

    transient Node<T> first;
    transient Node<T> last;
    private transient int count;
    private final int capacity;
    final ReentrantLock lock = new ReentrantLock();
    
    private final Condition notTmpty = this.lock.newCondition();

    private final Condition notFull = this.lock.newCondition();
    
    public PluggableLinkedBlockingDueue()
    {
        this(Integer.MAX_VALUE);
    }

    public PluggableLinkedBlockingDueue(int paramInt)
    {
        if (paramInt <= 0)
            throw new IllegalArgumentException();
        this.capacity = paramInt;
    }

    public PluggableLinkedBlockingDueue(Collection<? extends T> paramCollection)
    {
        this(Integer.MAX_VALUE);
        ReentrantLock localReentrantLock = this.lock;
        localReentrantLock.lock();
        try
        {
            Iterator<? extends T> localIterator = paramCollection.iterator();
            while (localIterator.hasNext())
            {
                T localObject1 = localIterator.next();
                if (localObject1 == null)
                    throw new NullPointerException();
                if (!linkLast(localObject1))
                    throw new IllegalStateException("Deque full");
            }
        } finally
        {
            localReentrantLock.unlock();
        }
    }

    @Override
    public int remainingCapacity()
    {
        ReentrantLock localReentrantLock = lock;
        localReentrantLock.lock();
        try
        {
            int i = capacity - count;
            return i;
        } finally
        {
            localReentrantLock.unlock();
        }
    }

    @Override
    public int drainTo(Collection<? super T> paramCollection)
    {
        return drainTo(paramCollection, Integer.MAX_VALUE);
    }

    @Override
    public int drainTo(Collection<? super T> paramCollection, int paramInt)
    {
        if (paramCollection == null)
        {
            throw new NullPointerException();
        }
        if (paramCollection == this)
        {
            throw new IllegalArgumentException();
        }
        ReentrantLock localReentrantLock = lock;
        localReentrantLock.lock();
        try
        {
            int i = Math.min(paramInt, count);
            for (int j = 0; j < i; j++)
            {
                paramCollection.add(first.item);
                unlinkFirst();
            }
            return i;
        } finally
        {
            localReentrantLock.unlock();
        }
    }

    @Override
    public T removeFirst()
    {
        Object localObject = pollFirst();
        if (localObject == null)
        {
            throw new NoSuchElementException();
        }
        return (T) localObject;
    }

    @Override
    public T removeLast()
    {
        Object localObject = pollLast();
        if (localObject == null)
        {
            throw new NoSuchElementException();
        }
        return (T) localObject;
    }

    @Override
    public T pollFirst()
    {
        ReentrantLock localReentrantLock = lock;
        localReentrantLock.lock();
        try
        {
            Object localObject1 = unlinkFirst();
            return (T) localObject1;
        } finally
        {
            localReentrantLock.unlock();
        }
    }

    @Override
    public T pollLast()
    {
        ReentrantLock localReentrantLock = lock;
        localReentrantLock.lock();
        try
        {
            Object localObject1 = unlinkLast();
            return (T) localObject1;
        } finally
        {
            localReentrantLock.unlock();
        }
    }

    @Override
    public T getFirst()
    {
        Object localObject = peekFirst();
        if (localObject == null)
        {
            throw new NoSuchElementException();
        }
        return (T) localObject;
    }

    @Override
    public T getLast()
    {
        Object localObject = peekLast();
        if (localObject == null)
        {
            throw new NoSuchElementException();
        }
        return (T) localObject;
    }

    @Override
    public T peekFirst()
    {
        ReentrantLock localReentrantLock = lock;
        localReentrantLock.lock();
        try
        {
            Object localObject1 = first == null ? null : first.item;
            return (T) localObject1;
        } finally
        {
            localReentrantLock.unlock();
        }
    }

    @Override
    public T peekLast()
    {
        ReentrantLock localReentrantLock = lock;
        localReentrantLock.lock();
        try
        {
            Object localObject1 = last == null ? null : last.item;
            return (T) localObject1;
        } finally
        {
            localReentrantLock.unlock();
        }
    }

    @Override
    public T pop()
    {
        return (T) removeFirst();
    }

    public boolean remove(Object paramObject)
    {
        return removeFirstOccurrence(paramObject);
    }

    @Override
    public Iterator<T> descendingIterator()
    {
        return new DescendingItr();
    }

    @Override
    public void addFirst(T paramT)
    {
        if (!offerFirst(paramT))
        {
            throw new IllegalStateException("Deque full");
        }
    }

    @Override
    public void addLast(T paramT)
    {
        if (!offerLast(paramT))
        {
            throw new IllegalStateException("Deque full");
        }
    }

    @Override
    public boolean offerFirst(T paramT)
    {
        if (paramT == null)
        {
            throw new NullPointerException();
        }
        ReentrantLock localReentrantLock = lock;
        localReentrantLock.lock();
        try
        {
            boolean bool = linkFirst(paramT);
            return bool;
        } finally
        {
            localReentrantLock.unlock();
        }
    }

    @Override
    public boolean offerLast(T paramT)
    {
        if (paramT == null)
        {
            throw new NullPointerException();
        }
        ReentrantLock localReentrantLock = lock;
        localReentrantLock.lock();
        try
        {
            boolean bool = linkLast(paramT);
            return bool;
        } finally
        {
            localReentrantLock.unlock();
        }
    }

    @Override
    public void putFirst(T paramT) throws InterruptedException
    {
        if (paramT == null)
        {
            throw new NullPointerException();
        }
        ReentrantLock localReentrantLock = lock;
        localReentrantLock.lock();
        try
        {
            while (!linkFirst(paramT))
            {
                notFull.await();
            }
        } finally
        {
            localReentrantLock.unlock();
        }
    }

    @Override
    public void putLast(T paramT) throws InterruptedException
    {
        if (paramT == null)
        {
            throw new NullPointerException();
        }
        ReentrantLock localReentrantLock = lock;
        localReentrantLock.lock();
        try
        {
            while (!linkLast(paramT))
            {
                notFull.await();
            }
        } finally
        {
            localReentrantLock.unlock();
        }
    }

    @Override
    public boolean offerFirst(T paramT, long paramLong, TimeUnit paramTimeUnit) throws InterruptedException
    {
        if (paramT == null)
        {
            throw new NullPointerException();
        }
        long l = paramTimeUnit.toNanos(paramLong);
        ReentrantLock localReentrantLock = lock;
        localReentrantLock.lockInterruptibly();
        try
        {
            while (!linkFirst(paramT))
            {
                if (l <= 0L)
                {
                    return false;
                }
                l = notFull.awaitNanos(l);
            }
            boolean bool = true;
            return bool;
        } finally
        {
            localReentrantLock.unlock();
        }
    }

    @Override
    public boolean offerLast(T paramT, long paramLong, TimeUnit paramTimeUnit) throws InterruptedException
    {
        if (paramT == null)
        {
            throw new NullPointerException();
        }
        long l = paramTimeUnit.toNanos(paramLong);
        ReentrantLock localReentrantLock = lock;
        localReentrantLock.lockInterruptibly();
        try
        {
            while (!linkLast(paramT))
            {
                if (l <= 0L)
                {
                    return false;
                }
                l = notFull.awaitNanos(l);
            }
            boolean bool = true;
            return bool;
        } finally
        {
            localReentrantLock.unlock();
        }
    }

    @Override
    public T takeFirst() throws InterruptedException
    {
        ReentrantLock localReentrantLock = lock;
        localReentrantLock.lock();
        try
        {
            Object localObject1;
            while ((localObject1 = unlinkFirst()) == null)
            {
                notTmpty.await();
            }
            Object localObject2 = localObject1;
            return (T) localObject2;
        } finally
        {
            localReentrantLock.unlock();
        }
    }

    @Override
    public T takeLast() throws InterruptedException
    {
        ReentrantLock localReentrantLock = lock;
        localReentrantLock.lock();
        try
        {
            Object localObject1;
            while ((localObject1 = unlinkLast()) == null)
            {
                notTmpty.await();
            }
            Object localObject2 = localObject1;
            return (T) localObject2;
        } finally
        {
            localReentrantLock.unlock();
        }
    }

    @Override
    public T pollFirst(long paramLong, TimeUnit paramTimeUnit) throws InterruptedException
    {
        long l = paramTimeUnit.toNanos(paramLong);
        ReentrantLock localReentrantLock = lock;
        localReentrantLock.lockInterruptibly();
        try
        {
            Object localObject1;
            while ((localObject1 = unlinkFirst()) == null)
            {
                if (l <= 0L)
                {
                    return null;
                }
                l = notTmpty.awaitNanos(l);
            }
            Object localObject2 = localObject1;
            return (T) localObject2;
        } finally
        {
            localReentrantLock.unlock();
        }
    }

    @Override
    public T pollLast(long paramLong, TimeUnit paramTimeUnit) throws InterruptedException
    {
        long l = paramTimeUnit.toNanos(paramLong);
        ReentrantLock localReentrantLock = lock;
        localReentrantLock.lockInterruptibly();
        try
        {
            Object localObject1;
            while ((localObject1 = unlinkLast()) == null)
            {
                if (l <= 0L)
                {
                    return null;
                }
                l = notTmpty.awaitNanos(l);
            }
            Object localObject2 = localObject1;
            return (T) localObject2;
        } finally
        {
            localReentrantLock.unlock();
        }
    }

    @Override
    public boolean removeFirstOccurrence(Object paramObject)
    {
        if (paramObject == null)
        {
            return false;
        }
        ReentrantLock localReentrantLock = lock;
        localReentrantLock.lock();
        try
        {
            for (Node<T> localNode = first; localNode != null; localNode = localNode.next)
            {
                if (paramObject.equals(localNode.item))
                {
                    unlink(localNode);
                    return true;
                }
            }
            boolean bool1 = false;
            return bool1;
        } finally
        {
            localReentrantLock.unlock();
        }
    }

    @Override
    public boolean removeLastOccurrence(Object paramObject)
    {
        if (paramObject == null)
        {
            return false;
        }
        ReentrantLock localReentrantLock = lock;
        localReentrantLock.lock();
        try
        {
            for (Node<T> localNode = last; localNode != null; localNode = localNode.prev)
            {
                if (paramObject.equals(localNode.item))
                {
                    unlink(localNode);
                    boolean bool2 = true;
                    return bool2;
                }
            }
            boolean bool1 = false;
            return bool1;
        } finally
        {
            localReentrantLock.unlock();
        }
    }

    @Override
    public boolean offer(T paramT)
    {
        return offerLast(paramT);
    }

    @Override
    public void put(T paramT) throws InterruptedException
    {
        putLast(paramT);
    }

    @Override
    public boolean offer(T paramT, long paramLong, TimeUnit paramTimeUnit) throws InterruptedException
    {
        return offerLast(paramT, paramLong, paramTimeUnit);
    }

    @Override
    public T poll()
    {
        return (T) pollFirst();
    }

    @Override
    public T take() throws InterruptedException
    {
        return (T) takeFirst();
    }

    @Override
    public T poll(long paramLong, TimeUnit paramTimeUnit) throws InterruptedException
    {
        return (T) pollFirst(paramLong, paramTimeUnit);
    }

    @Override
    public T peek()
    {
        return (T) peekFirst();
    }

    @Override
    public void push(T paramT)
    {
        addFirst(paramT);
    }

    @Override
    public Iterator<T> iterator()
    {
        return new Itr();
    }

    @Override
    public int size()
    {
        ReentrantLock localReentrantLock = lock;
        localReentrantLock.lock();
        try
        {
            int i = count;
            return i;
        } finally
        {
            localReentrantLock.unlock();
        }
    }

    @Override
    public boolean add(int index, T t)
    {
        if (offer(index, t))
            return true;
        else
            throw new IllegalStateException("Queue full");
    }
    
    @Override
    public boolean addBefore(T coordinate, T t)
    {
        ReentrantLock localReentrantLock = lock;
        localReentrantLock.lock();
        try
        {
            int index = indexOf(coordinate);
            if (index < 0)
                throw new IllegalArgumentException("coordinate not found");
            return add(index, t);
        } finally
        {
            localReentrantLock.unlock();
        }
    }
    
    @Override
    public boolean addAfter(T coordinate, T t)
    {
        ReentrantLock localReentrantLock = lock;
        localReentrantLock.lock();
        try
        {
            int index = indexOf(coordinate);
            if (index < 0)
                throw new IllegalArgumentException("coordinate not found");
            index++;
            return add(index, t);
        } finally
        {
            localReentrantLock.unlock();
        }
    }
    
    @Override
    public boolean offer(int index, T t)
    {
        if (t == null)
        {
            throw new NullPointerException();
        }
        ReentrantLock localReentrantLock = lock;
        localReentrantLock.lock();
        try
        {
            if (index == 0)
            {
                return linkFirst(t);
            } else
            {
                return linkAfter(t, entry(index - 1));
            }
        } finally
        {
            localReentrantLock.unlock();
        }
    }
    
    @Override
    public boolean offerBefore(T coordinate, T t)
    {
        ReentrantLock localReentrantLock = lock;
        localReentrantLock.lock();
        try
        {
            int index = indexOf(coordinate);
            if (index < 0)
                return false;
            return offer(index, t);
        } finally
        {
            localReentrantLock.unlock();
        }
    }
    
    @Override
    public boolean offerAfter(T coordinate, T t)
    {
        ReentrantLock localReentrantLock = lock;
        localReentrantLock.lock();
        try
        {
            int index = indexOf(coordinate);
            if (index < 0)
                return false;
            index++;
            return offer(index, t);
        } finally
        {
            localReentrantLock.unlock();
        }
    }
    
    @Override
    public void put(int index, T t) throws InterruptedException
    {
        if (t == null)
        {
            throw new NullPointerException();
        }
        ReentrantLock localReentrantLock = lock;
        localReentrantLock.lock();
        try
        {
            if (index == 0)
            {
                while (!linkFirst(t))
                {
                    notFull.await();
                }
            } else
            {
                while (!linkAfter(t, node(index - 1)))
                {
                    notFull.await();
                }
            }
        } finally
        {
            localReentrantLock.unlock();
        }
    }
    
    @Override
    public void putBefore(T coordinate, T t) throws InterruptedException
    {
        ReentrantLock localReentrantLock = lock;
        localReentrantLock.lock();
        try
        {
            int index = indexOf(coordinate);
            if (index < 0)
                throw new IllegalArgumentException("coordinate not found");
            put(index, t);
        } finally
        {
            localReentrantLock.unlock();
        }
    }
    
    @Override
    public void putAfter(T coordinate, T t) throws InterruptedException
    {
        ReentrantLock localReentrantLock = lock;
        localReentrantLock.lock();
        try
        {
            int index = indexOf(coordinate);
            if (index < 0)
                throw new IllegalArgumentException("coordinate not found");
            index++;
            put(index, t);
        } finally
        {
            localReentrantLock.unlock();
        }
    }
    
    @Override
    public boolean offer(int index, T t, long paramLong, TimeUnit paramTimeUnit) throws InterruptedException
    {
        if (t == null)
        {
            throw new NullPointerException();
        }
        long l = paramTimeUnit.toNanos(paramLong);
        ReentrantLock localReentrantLock = lock;
        localReentrantLock.lockInterruptibly();
        try
        {
            if (index == 0)
            {
                while (!linkFirst(t))
                {
                    if (l <= 0L)
                    {
                        return false;
                    }
                    l = notFull.awaitNanos(l);
                }
            } else
            {
                while (!linkAfter(t, node(index - 1)))
                {
                    if (l <= 0L)
                    {
                        return false;
                    }
                    l = notFull.awaitNanos(l);
                }
            }
            return true;
        } finally
        {
            localReentrantLock.unlock();
        }
    }
    
    @Override
    public boolean offerBefore(T coordinate, T t, long paramLong, TimeUnit paramTimeUnit) throws InterruptedException
    {
        ReentrantLock localReentrantLock = lock;
        localReentrantLock.lock();
        try
        {
            int index = indexOf(coordinate);
            if (index < 0)
                throw new IllegalArgumentException("coordinate not found");
            return offer(index, t, paramLong, paramTimeUnit);
        } finally
        {
            localReentrantLock.unlock();
        }
    }
    
    @Override
    public boolean offerAfter(T coordinate, T t, long paramLong, TimeUnit paramTimeUnit) throws InterruptedException
    {
        ReentrantLock localReentrantLock = lock;
        localReentrantLock.lock();
        try
        {
            int index = indexOf(coordinate);
            if (index < 0)
                throw new IllegalArgumentException("coordinate not found");
            index++;
            return offer(index, t, paramLong, paramTimeUnit);
        } finally
        {
            localReentrantLock.unlock();
        }
    }
    
    private boolean linkAfter(T e, Node<T> paramTntry)
    {
        if (count >= capacity || paramTntry == null)
        {
            return false;
        }
        Node<T> localTntry = new Node<T>(e, paramTntry, paramTntry.next);
        if (localTntry.prev != null)
        {
            localTntry.prev.next = localTntry;
        }
        if (localTntry.next != null)
        {
            localTntry.next.prev = localTntry;
        }
        if (paramTntry == last)
        {
            last = localTntry;
        }
        count += 1;
        notTmpty.signal();
        return true;
    }

    @Override
    public T get(int index)
    {
        ReentrantLock localReentrantLock = lock;
        localReentrantLock.lock();
        try
        {
            return entry(index).item;
        } finally
        {
            localReentrantLock.unlock();
        }
    }

    /**
     * 检查（大的合法性）
     * @param index
     * @return
     */
    private Node<T> entry(int index)
    {
        if ((index < 0) || (index >= count))
        {
            throw new IndexOutOfBoundsException("Index: " + index + ", Size: " + count);
        }
        return node(index);
    }
    
    /**
     * 不检查(大的合法性)
     * @param index
     * @return
     */
    private Node<T> node(int index)
    {
        if (index < 0)
        {
            throw new IndexOutOfBoundsException("Index: " + index + ", Size: " + count);
        }
        if (index >= count)
        {
            return null;
        }
        int i;
        Node<T> localTntry = null;
        if (index < count >> 1)
        {
            localTntry = first;
            for (i = 0; i < index; i++)
            {
                localTntry = localTntry.next;
                if (localTntry == null)
                {
                    break;
                }
            }
        } else
        {
            localTntry = last;
            for (i = count; i > index + 1; i--)
            {
                localTntry = localTntry.prev;
                if (localTntry == null)
                {
                    break;
                }
            }
        }
        return localTntry;
    }

    @Override
    public T remove(int index)
    {
        T x = poll(index);
        if (x != null)
            return x;
        else
            throw new NoSuchElementException();
    }
    
    @Override
    public T poll(int index)
    {
        ReentrantLock localReentrantLock = lock;
        localReentrantLock.lock();
        try
        {
            Node<T> node = entry(index);
            return unlink(node);
        } finally
        {
            localReentrantLock.unlock();
        }
    }
    
    @Override
    public T take(int index) throws InterruptedException
    {
        ReentrantLock localReentrantLock = lock;
        localReentrantLock.lock();
        try
        {
            T localT = null;
            while ((localT = unlink(index)) == null)
            {
                notTmpty.await();
            }
            return localT;
        } finally
        {
            localReentrantLock.unlock();
        }
    }
    
    @Override
    public T take(int index, long time, TimeUnit unit) throws InterruptedException
    {
        long nanosTimeout = unit.toNanos(time);
        ReentrantLock localReentrantLock = lock;
        localReentrantLock.lock();
        try
        {
            T localT = null;
            while ((localT = unlink(index)) == null)
            {
                notTmpty.awaitNanos(nanosTimeout);
            }
            return localT;
        } finally
        {
            localReentrantLock.unlock();
        }
    }

    @Override
    public int indexOf(T t)
    {
        if (t == null)
        {
            throw new NullPointerException();
        }
        ReentrantLock localReentrantLock = lock;
        localReentrantLock.lock();
        try
        {
            if (count < 1)
            {
                return -1;
            }
            int i = 0;
            Node<T> localTntry = first;
            do
            {
                if (t.equals(localTntry.item))
                {
                    return i;
                }
                localTntry = localTntry.next;
                i++;
            } while (localTntry.next != null);
            if (t.equals(localTntry.item))
            {
                return i;
            }
            return -1;
        } finally
        {
            localReentrantLock.unlock();
        }
    }

    public boolean exchange(T paramOne, T paramTwo)
    {
    	ReentrantLock localReentrantLock = lock;
        localReentrantLock.lock();
        try
        {
        	Node<T> one = query(paramOne);
        	if (one == null)
        	{
        		throw new IllegalArgumentException("paramOne not found");
			}
        	Node<T> two = query(paramTwo);
        	if (two == null)
        	{
        		throw new IllegalArgumentException("paramTwo not found");
			}
        	return exchange(one, two);
        } finally
        {
            localReentrantLock.unlock();
        }
    }
    
    public boolean exchange(int indexOne, int indexTwo)
    {
    	ReentrantLock localReentrantLock = lock;
        localReentrantLock.lock();
        try
        {
        	if (indexOne == indexTwo)
        	{
				return false;
			}
        	Node<T> one = entry(indexOne);
        	if (one == null)
        	{
        		throw new IllegalArgumentException("indexOne not found");
			}
        	Node<T> two = entry(indexTwo);
        	if (two == null)
        	{
        		throw new IllegalArgumentException("indexTwo not found");
			}
        	return exchange(one, two);
        } finally
        {
            localReentrantLock.unlock();
        }
    }
    
    @Override
    public boolean moveBefore(T t, T coordinate)
    {
        ReentrantLock localReentrantLock = lock;
        localReentrantLock.lock();
        try
        {
            int check = indexOf(coordinate);
            if (check < 0)
            {
                throw new IllegalArgumentException("coordinate not found");
            }
            int local = queryAndRemove(t);
            if (local < 0)
            {
                throw new IllegalArgumentException("t not found");
            }
            if (local < check)
            {
                check--;
            }
            return add(check, t);
        } finally
        {
            localReentrantLock.unlock();
        }
    }

    @Override
    public boolean moveAfter(T t, T coordinate)
    {
        ReentrantLock localReentrantLock = lock;
        localReentrantLock.lock();
        try
        {
            int check = indexOf(coordinate);
            if (check < 0)
            {
                throw new IllegalArgumentException("coordinate not found");
            }
            int local = queryAndRemove(t);
            if (local < 0)
            {
                throw new IllegalArgumentException("t not found");
            }
            if (local <= check)
            {
                check--;
            }
            check ++;
            return add(check, t);
        } finally
        {
            localReentrantLock.unlock();
        }
    }

    
    private boolean exchange(Node<T> one, Node<T> two) 
    {
    	if (one == two)
    	{
			return false;
		}
    	
    	if (one == first)
    	{
    		first = two;
    		if (two == last)
    		{
    			last = one;
    		}
		} else if (one == last)
		{
			last = two;
			if (two == first)
    		{
				first = one;
    		}
		} else if (two == first)
		{
			first = one;
			if (one == last)
    		{
				last = two;
    		}
		} else if (two == last)
		{
			last = one;
			if (one == first)
    		{
				first = two;
    		}
		}
    	
    	Node<T> op = one.prev;
    	Node<T> on = one.next;
    	Node<T> tp = two.prev;
    	Node<T> tn = two.next;
    	
    	// 处理相邻问题
    	if (op == two)
    	{
    		if (tp != null)
    		{
				tp.next = one;
				one.prev = tp;
			} else
			{
				one.prev = null;
			}
    		one.next = two;
    		two.prev = one;
    		if (on != null)
    		{
				two.next = on;
				on.prev = two;
			} else
			{
				two.next = null;
			}
		} else if(on == two)
		{
			if (op != null)
			{
				op.next = two;
				two.prev = op;
			} else
			{
				two.prev = null;
			}
			two.next = one;
			one.prev = two;
			if (tn != null)
			{
				one.next = tn;
				tn.prev = one;
			} else
			{
				one.next = null;
			}
		} else 
		{
			// one two的前缀和后缀
        	if (op != null)
        	{
        		op.next = two;
        		two.prev = op;
			} else
			{
				two.prev = null;
			}
        	if (on != null)
        	{
				two.next = on;
				on.prev = two;
			} else
			{
				two.next = null;
			}
        	if (tp != null)
        	{
        		tp.next = one;
        		one.prev = tp;
			} else
			{
				one.prev = null;
			}
        	if (tn != null)
        	{
				one.next = tn;
				tn.prev = one;
			} else
			{
				one.next = null;
			}
		}
    	first.prev = null;
    	last.next = null;
    	return true;
	}

	/**
     * 查询和param相等的在当前链表的节点
     * @param param
     * @return
     */
    private Node<T> query(T param)
    {
    	if (param == null)
        {
            return null;
        }
        ReentrantLock localReentrantLock = lock;
        localReentrantLock.lock();
        try
        {
            for (Node<T> localNode = first; localNode != null; localNode = localNode.next)
            {
                if (param == localNode.item || param.equals(localNode.item))
                {
                    return localNode;
                }
            }
            return null;
        } finally
        {
            localReentrantLock.unlock();
        }
    }
    
    /**
     * 查询和param相等的在当前链表的节点,并移除它
     * @param param
     * @return
     */
    private int queryAndRemove(T param)
    {
        if (param == null)
        {
            return -1;
        }
        ReentrantLock localReentrantLock = lock;
        localReentrantLock.lock();
        try
        {
            int index = -1;
            for (Node<T> localNode = first; localNode != null; localNode = localNode.next)
            {
                index ++;
                if (param == localNode.item || param.equals(localNode.item))
                {
                    unlink(localNode);
                    return index;
                }
            }
            return -1;
        } finally
        {
            localReentrantLock.unlock();
        }
    }
    
    private boolean linkFirst(T paramT)
    {
        if (count >= capacity)
        {
            return false;
        }
        Node<T> localNode1 = first;
        Node<T> localNode2 = new Node<T>(paramT, null, localNode1);
        first = localNode2;
        if (last == null)
        {
            last = localNode2;
        } else
        {
            localNode1.prev = localNode2;
        }
        count += 1;
        notTmpty.signal();
        return true;
    }

    private boolean linkLast(T paramT)
    {
        if (count >= capacity)
        {
            return false;
        }
        Node<T> localNode1 = last;
        Node<T> localNode2 = new Node<T>(paramT, localNode1, null);
        last = localNode2;
        if (first == null)
        {
            first = localNode2;
        } else
        {
            localNode1.next = localNode2;
        }
        count += 1;
        notTmpty.signal();
        return true;
    }

    private T unlinkFirst()
    {
        Node<T> localNode1 = this.first;
        if (localNode1 == null)
            return null;
        Node<T> localNode2 = localNode1.next;
        Object localObject = localNode1.item;
        localNode1.item = null;
        localNode1.next = localNode1;
        this.first = localNode2;
        if (localNode2 == null)
            this.last = null;
        else
            localNode2.prev = null;
        this.count -= 1;
        this.notFull.signal();
        return (T) localObject;
    }

    private T unlinkLast()
    {
        Node<T> localNode1 = this.last;
        if (localNode1 == null)
            return null;
        Node<T> localNode2 = localNode1.prev;
        Object localObject = localNode1.item;
        localNode1.item = null;
        localNode1.prev = localNode1;
        this.last = localNode2;
        if (localNode2 == null)
            this.first = null;
        else
            localNode2.next = null;
        this.count -= 1;
        this.notFull.signal();
        return (T) localObject;
    }
    
    private T unlink(int index)
    {
        Node<T> node = node(index);
        if (node == null)
        {
            return null;
        }
        return unlink(node);
    }

    T unlink(Node<T> paramNode)
    {
        Node<T> localNode1 = paramNode.prev;
        Node<T> localNode2 = paramNode.next;
        if (localNode1 == null)
        {
            return unlinkFirst();
        } else if (localNode2 == null)
        {
            return unlinkLast();
        } else
        {
            localNode1.next = localNode2;
            localNode2.prev = localNode1;
            T result = paramNode.item;
            paramNode.item = null;
            this.count -= 1;
            this.notFull.signal();
            return result;
        }
    }

    private void writeObject(ObjectOutputStream paramObjectOutputStream) throws IOException
    {
        ReentrantLock localReentrantLock = this.lock;
        localReentrantLock.lock();
        try
        {
            paramObjectOutputStream.defaultWriteObject();
            for (Node<T> localNode = this.first; localNode != null; localNode = localNode.next)
                paramObjectOutputStream.writeObject(localNode.item);
            paramObjectOutputStream.writeObject(null);
        } finally
        {
            localReentrantLock.unlock();
        }
    }

    private void readObject(ObjectInputStream paramObjectInputStream) throws IOException, ClassNotFoundException
    {
        paramObjectInputStream.defaultReadObject();
        this.count = 0;
        this.first = null;
        this.last = null;
        while (true)
        {
            Object localObject = paramObjectInputStream.readObject();
            if (localObject == null)
                break;
            add((T) localObject);
        }
    }

    private abstract class AbstractItr implements Iterator<T>
    {
        PluggableLinkedBlockingDueue.Node<T> next;
        T nextItem;
        private PluggableLinkedBlockingDueue.Node<T> lastRet;

        abstract PluggableLinkedBlockingDueue.Node<T> firstNode();

        abstract PluggableLinkedBlockingDueue.Node<T> nextNode(PluggableLinkedBlockingDueue.Node<T> paramNode);

        AbstractItr()
        {
            ReentrantLock localReentrantLock = PluggableLinkedBlockingDueue.this.lock;
            localReentrantLock.lock();
            try
            {
                this.next = firstNode();
                this.nextItem = (this.next == null ? null : this.next.item);
            } finally
            {
                localReentrantLock.unlock();
            }
        }

        void advance()
        {
            ReentrantLock localReentrantLock = PluggableLinkedBlockingDueue.this.lock;
            localReentrantLock.lock();
            try
            {
                PluggableLinkedBlockingDueue.Node<T> localNode = nextNode(this.next);
                if (localNode == this.next)
                {
                    this.next = firstNode();
                } else
                {
                    while ((localNode != null) && (localNode.item == null))
                        localNode = nextNode(localNode);
                    this.next = localNode;
                }
                this.nextItem = (this.next == null ? null : this.next.item);
            } finally
            {
                localReentrantLock.unlock();
            }
        }

        public boolean hasNext()
        {
            return this.next != null;
        }

        public T next()
        {
            if (this.next == null)
                throw new NoSuchElementException();
            this.lastRet = this.next;
            Object localObject = this.nextItem;
            advance();
            return (T) localObject;
        }

        public void remove()
        {
            PluggableLinkedBlockingDueue.Node<T> localNode = this.lastRet;
            if (localNode == null)
                throw new IllegalStateException();
            this.lastRet = null;
            ReentrantLock localReentrantLock = PluggableLinkedBlockingDueue.this.lock;
            localReentrantLock.lock();
            try
            {
                if (localNode.item != null)
                    PluggableLinkedBlockingDueue.this.unlink(localNode);
            } finally
            {
                localReentrantLock.unlock();
            }
        }
    }

    @SuppressWarnings("rawtypes")
    private class DescendingItr extends PluggableLinkedBlockingDueue.AbstractItr
    {
        private DescendingItr()
        {
            super();
        }

        PluggableLinkedBlockingDueue.Node<T> firstNode()
        {
            return PluggableLinkedBlockingDueue.this.last;
        }

        PluggableLinkedBlockingDueue.Node<T> nextNode(PluggableLinkedBlockingDueue.Node paramNode)
        {
            return paramNode.prev;
        }
    }

    @SuppressWarnings("rawtypes")
    private class Itr extends PluggableLinkedBlockingDueue.AbstractItr
    {
        private Itr()
        {
            super();
        }

        PluggableLinkedBlockingDueue.Node<T> firstNode()
        {
            return PluggableLinkedBlockingDueue.this.first;
        }

        PluggableLinkedBlockingDueue.Node<T> nextNode(PluggableLinkedBlockingDueue.Node paramNode)
        {
            return paramNode.next;
        }
    }

    static final class Node<T>
    {
        T item;
        Node<T> prev;
        Node<T> next;

        Node(T paramT)
        {
            this.item = paramT;
        }

        Node(T paramT, Node<T> paramNode1, Node<T> paramNode2)
        {
            item = paramT;
            prev = paramNode1;
            next = paramNode2;
        }

    }
    
}
